<template>
  <el-container class="bg-white rounded">

    <el-header class='sysRole-header'>
      <el-button-group>
        <el-button text type='default' @click='refreshTable'><el-icon><Refresh /></el-icon><span>刷新</span></el-button>
        <el-button text type='primary' @click='handleNew'><el-icon><Plus /></el-icon><span>新增</span></el-button>
        <el-button text @click='handleUpdate'><el-icon><EditPen /></el-icon><span>修改</span></el-button>
        <el-popconfirm
          width="220"
          confirm-button-text="确定"
          cancel-button-text="取消"
          :icon="InfoFilled"
          icon-color="#626AEF"
          title="您确定要删除选中行吗？"
          @confirm="handleDelete"
        >
          <template #reference>
            <el-button text type='danger'><el-icon><CloseBold /></el-icon><span>删除</span></el-button>
          </template>
        </el-popconfirm>
      </el-button-group>

      <el-button-group>
        <el-tooltip class="box-item" effect="dark" content="导出" placement="top">
          <el-button text @click='handleExport'><img :src='excelPng' width='15' height='15'></el-button>
        </el-tooltip>
        <el-tooltip class="box-item" effect="dark" content="设置" placement="top">
          <el-button text @click='handleSetting'><el-icon><Setting /></el-icon></el-button>
        </el-tooltip>
      </el-button-group>
    </el-header>

    <el-main>
      <el-row>
        <el-table :key='tableKey'
                  :data="tableData.value" :row-key='primaryKeyFieldName' :current-row-key='currentRow.value["keyValue"]'
                  stripe border highlight-current-row empty-text='没有数据'
                  :header-cell-class-name='rowColor'
                  style="width: 100%; height: 100%" :table-layout='auto' v-loading='loading'
                  @cell-click='handleCellClick' @row-dblclick='handleRowDblClick' @current-change='handleCurrentChange'>
          <el-table-column type="index" align="center" :width="$store.state.style.seqColumnWidthEditIcon">
            <template #header>
<!--          :style='{color: $store.state.tableHeaderFontColor, fontWeight: $store.state.fontWeight}    -->
              <span>序号</span>
            </template>

            <!-- 默认插槽 -->
            <template #default='scope'>
              <!-- 编辑状态 -->
              <template v-if='editObj.value.keyValue === scope.row[primaryKeyFieldName]'>
                <div class='flex items-center justify-between'>
                  <el-tooltip class="box-item" effect="dark" content="保存" placement="top">
                    <img :src='SaveIcon' width='15' height='15' style='cursor: pointer' @click='handleSaveRow'>
                  </el-tooltip>
                  <el-tooltip class="box-item" effect="dark" content="取消" placement="top">
                    <img :src='CancelIcon' width='15' height='15' style='cursor: pointer' @click='handleCancelRow'>
                  </el-tooltip>
                </div>
              </template>
              <!-- 显示状态 -->
              <span v-else>{{scope.$index + 1}}</span>
            </template>
          </el-table-column>
          <template v-for='(item, index) in tableStyles.value' :key='item.fieldName'>
            <template v-if='item.visible'>
              <!--
                如果不在动态遍历列后面追加一个空白的列，并自动将最后一个动态列自适应宽度，则使用本注释中的代码
                <el-table-column :prop="item.fieldName" :width="index === $store.state.sysRole.tableStyle.length-1 ? 'auto' : item.widthPx" >
              -->
              <el-table-column :prop="item.fieldName" :width="item.widthPx" :sortable='item.sortable === 1 ? true : false'>
                <!-- 插槽 header -->
                <template #header class='flex items-center'>
<!--                    <span :style='{color: $store.state.tableHeaderFontColor}'>{{ item.cn }}</span>-->
                  <filter-header :table-style-record='item' :option-array='filterOptions[item.fieldName]'
                                 v-if='item.filter' :key='state.timer'
                                      @click.stop.prevent @confirm='handleFilterConfirm' @cancel='handleFilterCancel'></filter-header>
                  <span v-else>{{ item.cn }}</span>
                </template>

                <!-- 默认插槽 -->
                <template #default='scope'>
                  <!-- 编辑状态 -->
                  <template v-if='editObj.value.keyValue === scope.row[primaryKeyFieldName]'>
                    <template v-if='item.ctlType === "checkbox"'>
                      <el-checkbox v-model='editObj.value.data[item.fieldName]' size='large'/>
                    </template>
                    <template v-else-if='item.ctlType === "date"'>
                      <el-date-picker v-model="editObj.value.data[item.fieldName]" type="date" size="default" prefix-icon='' class='date-in-table'/>
                    </template>
                    <template v-else-if='item.ctlType === "select"'>
                      <el-select v-model="editObj.value.data[item.fieldName]" class="m-2" placeholder="选择">
                        <el-option
                          v-for="selectItem in dropDownMap.value[item.fieldName]"
                          :key="selectItem[tableStyleMap.value[item.fieldName]?.selectOpts.meta.key]"
                          :label="selectItem[tableStyleMap.value[item.fieldName]?.selectOpts.meta.label]"
                          :value="selectItem[tableStyleMap.value[item.fieldName]?.selectOpts.meta.value]"
                        />
                      </el-select>
                    </template>
                    <el-input v-else v-model='editObj.value.data[item.fieldName]' @dblclick.prevent.stop></el-input>
                  </template>
                  <!-- 显示状态 -->
                  <span v-else>{{ scope.row[item.fieldName] }}</span>
                </template>

              </el-table-column>
            </template>
          </template>
          <el-table-column label='' width='auto'></el-table-column>
        </el-table>
      </el-row>
    </el-main>
  </el-container>

  <export-2-excel v-model='export2ExcelVisible' :records='tableData.value' :header-map='headerMap' :defaultFileName='defaultExcelFileName'></export-2-excel>

  <!-- 编辑表格样式数据的对话框 -->
  <el-dialog v-model="visibleStyleTableDialog" width='700px' draggable>
    <style-table :table-name='tableName' @save='afterStyleSave' @cancel='afterStyleCancel'></style-table>
  </el-dialog>

</template>
<script setup>
import { ref, reactive, watch } from 'vue'
import { useStore } from 'vuex'
import { useToast } from 'vue-toastification'
import Export2Excel from '~/components/Export2Excel.vue'
import { getTableStyle, tableStyle2ExportHeaderMap } from '~/utils/sysUtils'
import excelPng from '~/assets/icon/excel.png'
import FilterHeader from '~/components/filterHeader/index.vue'
import { constant } from '~/utils/globalv'
import { getDistFieldValArray, getRowIndexInObjArray } from '~/utils/arrayUtils'
import StyleTable from '~/components/styleTable/index.vue'
import SaveIcon from '~/assets/icon/save.png'
import CancelIcon from '~/assets/icon/cancel.png'
import { isValuable } from '~/utils/objectUtils'
import { CurrentRow as CurrentRowClass, EditObj as EditObjClass } from '~/utils/tableUtils'
import { getCtlTypeMap, getRemoteData } from '~/utils/tableStyleResolver'

const props = defineProps({
  tableName: {// 数据库表名称，例如：sys_role
    type: String,
    required: true
  },
  saveStoreUrl: {// store模块保存API - 新增+修改
    type: String,
    required: true
  },
  deleteStoreUrl: {// store模块删除API
    type: String,
    required: true
  },
  listStoreUrl: {// store模块查询显示API
    type: String,
    required: true
  },
  defaultExcelFileName: {// 导出excel默认文件名
    type: String,
    required: true
  },
  primaryKeyFieldName: {// 表sys_role主键字段
    type: String,
    default: 'iid'
  },
  sortFieldName: {// 表sys_role排序字段，要求后台字段为数值类型
    type: String,
    default: 'seq'
  }
})

// 原本设计增删改发送事件给父组件完成，后来使用行内编辑在本组件内实现
// const emits = defineEmits(['addNew','edit', 'delete'])

const tableKey = ref(Math.random())// 表格刷新
const state = reactive({timer:0})// 类似 tableKey 功能
let tableDataAll = []
const toast = useToast()
const store = useStore()
const loading = ref(false)// 表格加载状态
const export2ExcelVisible = ref(false)
let headerMap = []// 导出后excel头中英文对照
let tableStyles = reactive({value:[]})
const filterOptions = {}
const visibleStyleTableDialog = ref(false)
// 用户鼠标左键点击的行，keyValue = 行数据主键值，rowIndex = 行号
const currentRow = reactive({ value: new CurrentRowClass()})
const editObj = reactive({value: new EditObjClass()})// 编辑状态对象
const tableData = reactive({value: []})
const tableStyleMap = reactive({value:{}})
const dropDownMap = reactive({value:{field01: [], field02: []}})

const flushTableStyle = () => {
  const styleData = getTableStyle(props.tableName)
  styleData.sort((a, b) => a[props.sortFieldName] - b[props.sortFieldName])
  tableStyles.value = styleData
  tableStyleMap.value = getCtlTypeMap(styleData)
  getRemoteData(tableStyles.value).then(res => {
    dropDownMap.value = res
  })

  headerMap = tableStyle2ExportHeaderMap(props.tableName)
  refreshFilterOptions()
  tableKey.value = Math.random()
}

// 请求后台数据
const reqTableData = () => {
  loading.value = true
  store.dispatch(props.listStoreUrl).then(res => {
    if(res.code !== 1) return
    tableData.value = res.data
    tableDataAll = res.data
    refreshFilterOptions()
  }).finally(() => loading.value = false)
}
const refreshTable = () => {
  loading.value = true
  flushTableStyle()
  reqTableData()

  // 恢复选中、编辑状态
  currentRow.value.reset()
  editObj.value.reset()
}

const rowColor = (rowindex) => {
  return 'darkgray-color';
}

const handleCellClick = (row, column, cell, event) => {
  currentRow.value.keyValue = row[props.primaryKeyFieldName]
  currentRow.value.rowIndex = getRowIndexInObjArray(tableData.value, props.primaryKeyFieldName, currentRow.value.keyValue)
}

const handleUpdate = () => {
  if(!isValuable(currentRow.value.keyValue)){
    toast('选中任意一行后再执行本操作！')
    return
  }
  const rowData = tableData.value.filter(item => item[props.primaryKeyFieldName] === currentRow.value.keyValue)[0]
  editObj.value.data = {...rowData}
  editObj.value.keyValue = currentRow.value.keyValue
}

// 执行删除请求
const handleDelete = () => {
  if(!currentRow.value.keyValue){
    toast('选中任意一行后再执行本操作！')
    return
  }

  store.dispatch(props.deleteStoreUrl, currentRow.value.keyValue).then(res => {
    if(res.code !== 1) return
    reqTableData()
    currentRow.value.reset()// 重置当前行
  })
}

const handleRowDblClick = (row, column, event) => {
  editObj.value.data = {...row}
  editObj.value.keyValue = row[props.primaryKeyFieldName]
  editObj.value.rowIndex = getRowIndexInObjArray(tableData.value, props.primaryKeyFieldName, row[props.primaryKeyFieldName])
}

const handleExport = () => {
  export2ExcelVisible.value = true
}

// 执行过滤操作
const handleFilterConfirm = ( tableStyleRecord, filterVal ) => {
  const fieldName = tableStyleRecord.fieldName

  if(tableStyleRecord.filter === constant.filter.fuzzyString)
    tableData.value = tableDataAll.filter(item => item[fieldName].indexOf(filterVal) >= 0)

  if(tableStyleRecord.filter === constant.filter.singleSelect)
    tableData.value = tableDataAll.filter(item => item[fieldName] == filterVal)

  if(tableStyleRecord.filter === constant.filter.multSelect)
    tableData.value = tableDataAll.filter(item => filterVal.find(opt => opt == item[fieldName]) ? true : false)
}

// 执行过滤取消操作
const handleFilterCancel = fieldName => {
  tableData.value = tableDataAll
}

// 为过滤功能为单选、多选的列准备去重的数据
const refreshFilterOptions = () => {
  for (const record of tableStyles.value) {
    if(!record.filter) continue
    if(record.filter === constant.filter.fuzzyString) continue

    const fieldName = record.fieldName
    if(record.filter === constant.filter.singleSelect || record.filter === constant.filter.multSelect){
      filterOptions[fieldName] = getDistFieldValArray(tableDataAll, fieldName)
    }
  }
  state.timer = new Date().getTime()
}

// 打开表格设置页面
const handleSetting = () => {
  visibleStyleTableDialog.value = true
}

const afterStyleSave = () => {
  flushTableStyle()
  visibleStyleTableDialog.value = false
}
const afterStyleCancel = () => visibleStyleTableDialog.value = false

// 取消行编辑
const handleCancelRow = () => {
  editObj.value.reset()
}

// 保存行编辑
const handleSaveRow = () => {
  if(editObj.value.data.iid === -1) editObj.value.data.iid = null
  else tableData.value.splice(editObj.value.rowIndex, 1, editObj.value.data)

  // 先排序再保存
  let i = 0
  for (const item of tableData.value) {
    item[props.sortFieldName] = i++
  }
  const reqParam = {record: editObj.value.data, records: tableData.value, recordRowIndex: editObj.value.rowIndex}
  store.dispatch(props.saveStoreUrl, reqParam).then(res => {
    if(res.code !== 1) toast.error(res.msg)
    editObj.value.reset()
  })
}

// 工具栏按钮新增，没有选中行则在数组末尾新增
// 有选中行则在其下新增
const handleNew = () => {
  editObj.value.reset()
  let editRowIndex = tableData.value.length
  if(currentRow.value.rowIndex >= 0 ) editRowIndex = currentRow.value.rowIndex + 1
  editObj.value.keyValue = -1

  // 构建新数据
  const newData = setDefault4NewRecord() || {}
  newData[props.primaryKeyFieldName] = -1
  editObj.value.data = newData

  editObj.value.rowIndex = editRowIndex
  tableData.value.splice(editRowIndex, 0, editObj.value.data)
}

const handleCurrentChange = (currentRow, oldCurrentRow) => {

}

// 设置默认值
const setDefault4NewRecord = () => {
  const defaultArray = tableStyles.value.filter(item => item.defaultValue && item.defaultValue.length > 0)
  if(!defaultArray || defaultArray.length === 0) return null
  const ret = {}
  defaultArray.forEach(item => {
    if(item.fieldType === 'date') ret[item.fieldName] = new Date()
    if(item.fieldType === 'string') ret[item.fieldName] = item.defaultValue
  })
  return ret
}

refreshTable()
defineExpose({ handleDelete, reqTableData })

</script>
<style scoped>
:deep() .darkgray-color {
  background-color: #f5f7fa !important;
}

.sysRole-header {
  border-bottom: 1px solid #eee;
  @apply flex items-center justify-between;
}

:deep() .el-table .caret-wrapper{
  display: none;
}

:deep() .date-in-table {
  width: 100%;
}

:deep() .el-input__prefix-inner {
  display: none;
}
</style>